package com.yunxin.download.server.infra.support.datasource;

import cn.hutool.core.text.CharSequenceUtil;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.yunxin.download.server.service.extenal.DownloadFileDTO;
import com.yunxin.download.server.infra.support.datasource.annotation.DataSourceDynamicSwitch;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @author zero°
 * @since 2023-06-15
 */
@Slf4j
@Aspect
@Component
public class DataSourceDynamicSwitchAop {

    private static final String LOG_CONTEXT = "AOP动态切换数据源，className:%s;dataSourceKey:%s";

    @Pointcut("@within(com.yunxin.download.server.infra.support.datasource.annotation.DataSourceDynamicSwitch) || @annotation(com.yunxin.download.server.infra.support.datasource.annotation.DataSourceDynamicSwitch)")
    public void pointcut() {
    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) {
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        //获取方法上的注解
        DataSourceDynamicSwitch annotationClass = method.getAnnotation(DataSourceDynamicSwitch.class);
        if (annotationClass == null) {
            //获取类上面的注解
            annotationClass = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), DataSourceDynamicSwitch.class);
            if (annotationClass == null) {
                return;
            }
        }
        //获取注解上的数据源的值的信息
        Object[] objects = joinPoint.getArgs();
        String dataSourceKey = getDataSourceKey(objects);
        //获取参数中的数据源
        if (CharSequenceUtil.isNotEmpty(dataSourceKey)) {
            //给当前的执行SQL的操作设置特殊的数据源的信息
            DynamicDataSourceContextHolder.push(dataSourceKey);
        } else {
            //参数中的数据源为空，则获取注解上的数据源
            dataSourceKey = annotationClass.value();
            DynamicDataSourceContextHolder.push(dataSourceKey);

        }
        log.info(String.format(LOG_CONTEXT, joinPoint.getTarget().getClass().getName(), CharSequenceUtil.isEmpty(dataSourceKey) ? "默认数据源" : dataSourceKey));
    }

    /**
     * 获取数据源名称
     * @param objects objects
     * @return String
     */
    private String getDataSourceKey(Object[] objects){
        StringBuilder result = new StringBuilder();
        for (Object object : objects) {
            result.append(getFieldValue(object.getClass(), object));
        }
        return result.toString();
    }

    private String getFieldValue(Class<?> cl, Object object){
        if (cl == null) {
            return "";
        }
        if (object instanceof DownloadFileDTO) {
            try {
                Field field = cl.getDeclaredField("dataSourceName");
                field.setAccessible(true);
                return field.get(object) + "";
            } catch (IllegalAccessException | NoSuchFieldException e) {
                log.warn("getFieldValue exception,e", e);
            }
        }
        return "";
    }

    @After("pointcut()")
    public void after(JoinPoint point) {
        //清理掉当前设置的数据源，让默认的数据源不受影响
        DynamicDataSourceContextHolder.clear();
    }
}
